#ifndef PROCESS_H_
#define PROCESS_H_

/*
Copyright (C) 2011 Salil Bhagurkar

This file is part of illusion

illusion is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

illusion is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with illusion.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <arch/process.h>
#include <kernel/vfs.h>
#include <kernel/vmpage.h>
#include <kernel/event.h>
#include <kernel/types.h>

extern struct vfs_node *vfs_process;

struct process;

struct process *get_process_by_pid(uint_t pid);
int create_process(struct process **ret_process, struct vfs_node *node, char *arguments, uint_t arguments_length, bool inherit_wn);
int create_kernel_process(struct process **ret_process, char *name, void (*main)());
int process_extend(struct process *process, long page_count);

struct process_file {
	//The file id which is associated with this process
	//The process will use this ID to refer to the locked file
	uint_t fid;
	//The state in which the file is open for the process
	uint_t state;
	//The vfs node to which this file corresponds
	struct vfs_node *node;
	struct process_file *next, *prev;
};

#define PROCESS_NAME_LEN 32
#define PROCESS_STACK_SIZE 8192
#define PROCESS_KERNEL_STACK_SIZE 8192

struct legal_fault;

#define PROCESS_STATE_RUN 0
#define PROCESS_STATE_SLEEP 1
#define PROCESS_STATE_EXIT 2

struct process_waitlist {
	//The process that is waiting
	struct process *process;
	struct process_waitlist *next, *prev;
};

struct process {
	bool is_kernel;							//Is this a kernel process?
	uint_t state;								//Running / sleeping
	struct process_waitlist *wait;			//The process_waitlist struct reverse pointer
	uint_t pid;								//Unique process ID
	uint_t prio;								//Process priority
	struct process_context process_context;		//The architecture dependent process context
	void *stack;							//The allocated stack
	uint_t stack_size;						//Size of the stack
	void *kernel_stack;						//Stack of the process when inside kernel
	uint_t kernel_stack_size;					//Size of the kernel stack
	char first_run;							//A boolean indicating if this is the first run (which means we don't have to read in a context)
	struct vfs_node *instance_fs;			//The vfs_node which has the instance information of this process
	struct vfs_node *process_fs;			//The vfs node which contains the data of this executable
	char name[PROCESS_NAME_LEN];			//The name of the process
	struct vmmap *vmmap;					//The vmmap for this process
	uint_t image_size;						//The total size of the initial image
	void (*main)();							//Entry of the process
	char *arguments;						//Arguments passed to the process
	uint_t arguments_length;					//The length of the buffer required to hold the arguments
	void *load, *end;						//The load address & end
	uint_t next_fid;							//The next available file ID
	struct process_file *files, *files_tail;	//The list of files opened by the process
	struct legal_fault *legal_faults,
		*legal_faults_tail;					//Legal fault regions registry (used for demand loading)
	struct vfs_node *vfs_node;				//Current working location of the process
	struct process *next, *prev;			//Linked list of processes.
	struct process_list *pl;				//The global process_list container
	struct vfs_node *redirect_out;			//Redirection for print
	uint_t redirect_out_idx;					//Index into the redirected file
	struct event *evt_run, *evt_sleep;		//Events raised when the process changes state
	struct event *evt_exit;					//Event raised when the process ends
	bool syscall_try;						//Syscalls are in try mode: they return error, instead of ending the process
};

void process_switch(struct process *from, struct process *to);
void process_kill(struct process *process);

void process_debug(struct process *process);

#endif /* PROCESS_H_ */
